package org.mokusakura.web.controller;

import org.mokusakura.constant.RequestAttributeKeyConstant;
import org.mokusakura.constant.ServletUrlConstant;
import org.mokusakura.constant.SessionAttributeKeyConstant;
import org.mokusakura.domain.Response;
import org.mokusakura.domain.User;
import org.mokusakura.persistence.Util.RegularExpressionVerifyUtil;
import org.mokusakura.service.UserService;
import org.mokusakura.web.util.RSAUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Map;
import java.util.Objects;


@Controller
public class AccountController {
    public static final String[] PARAMETER_KEY = {
            "newPassword", "bannerOption", "listOption", "favouriteCategoryId", "languagePreference", "phone",
            "country", "zip", "state", "city", "address2", "address1", "firstName", "lastName", "currentPassword"};
    public static final String BANNER_OPTION_SELECTED_STRING = "on";
    public static final String LIST_OPTION_SELECTED_STRING = "on";
    public static final String DEFAULT_FAVOURITE_CATEGORY_ID = "DEFAULT";
    public static final String EMAIL_TO_LOGIN = "email";
    public static final String PASSWORD_TO_LOGIN = "password";
    private final String publicKey;
    private final String privateKey;

    public AccountController() {
        Map<String, String> keyPair = RSAUtils.generateKeyPair();
        publicKey = keyPair.get(RSAUtils.PUBLIC_KEY);
        privateKey = keyPair.get(RSAUtils.PRIVATE_KEY);
    }


    @Autowired
    private UserService userService;

    @ResponseBody
    @GetMapping("/key")
    public String getKey() {
        return publicKey;
    }


    @ResponseBody
    @PostMapping(ServletUrlConstant.REGISTER_SERVLET_URL)
    public String register(@RequestBody User user, HttpSession session) {
        user.setPassword(RSAUtils.decrypt(user.getPassword(), privateKey));
        if (userService.getUserByEmail(user.getEmail()) != null) {
            return "Email Already Exit";
        }
        try {
            userService.register(user);
            session.setAttribute(SessionAttributeKeyConstant.LOGIN_USER, user);
            return "success";
        } catch (Exception e) {
            return e.getMessage();
        }

    }


    @PostMapping(ServletUrlConstant.CHANGE_ACCOUNT_INFORMATION_SERVLET_URL)
    public String ChangeAccountInformation(HttpServletRequest req,
                                           @SessionAttribute(SessionAttributeKeyConstant.LOGIN_USER) User user,
                                           Model model,
                                           HttpSession session) {
//        System.out.println("change");
        User newUser = new User();
        int index = 0;
        String newPassword = RSAUtils.decrypt(req.getParameter(PARAMETER_KEY[index++]), privateKey);
        newUser.setBannerOption(BANNER_OPTION_SELECTED_STRING.equals(req.getParameter(PARAMETER_KEY[index++])))
                .setListOption(LIST_OPTION_SELECTED_STRING.equals(req.getParameter(PARAMETER_KEY[index++])))
                .setFavouriteCategoryId(req.getParameter(PARAMETER_KEY[index++]))
                .setLanguagePreference(req.getParameter(PARAMETER_KEY[index++]))
                .setPhone(req.getParameter(PARAMETER_KEY[index++]))
                .setCountry(req.getParameter(PARAMETER_KEY[index++]))
                .setZip(req.getParameter(PARAMETER_KEY[index++]))
                .setState(req.getParameter(PARAMETER_KEY[index++]))
                .setCity(req.getParameter(PARAMETER_KEY[index++]))
                .setAddress2(req.getParameter(PARAMETER_KEY[index++]))
                .setAddress1(req.getParameter(PARAMETER_KEY[index++]))
                .setFirstName(req.getParameter(PARAMETER_KEY[index++]))
                .setLastName(req.getParameter(PARAMETER_KEY[index++]))
                .setId(user.getId())
                .setEmail(user.getEmail());
        String currentPassword = RSAUtils.decrypt(req.getParameter(PARAMETER_KEY[index]), privateKey);


        if (newPassword == null || newPassword.isEmpty()) {                 //不需要修改密码
            newUser.setPassword(user.getPassword());
        } else if (Objects.equals(currentPassword, user.getPassword())) {   //需要修改密码且成功验证
            if (RegularExpressionVerifyUtil.isLegalPassword(newPassword)) { //密码合法
                newUser.setPassword(newPassword);
            } else {                                                           //密码不非法
                model.addAttribute(RequestAttributeKeyConstant.UPDATE_ACCOUNT_INFORMATION_MESSAGE, "Illegal Password!");
                return "account/accountInformation";
            }

        } else {                                                          //需要修改密码但验证失败
            model.addAttribute(RequestAttributeKeyConstant.UPDATE_ACCOUNT_INFORMATION_MESSAGE, "Wrong Password!");
            return "account/accountInformation";
        }
        try {
            user = userService.update(newUser);
            session.setAttribute(SessionAttributeKeyConstant.LOGIN_USER, user);
            model.addAttribute(RequestAttributeKeyConstant.UPDATE_ACCOUNT_INFORMATION_MESSAGE, "Update Success!");

        } catch (Exception e) {
            model.addAttribute(RequestAttributeKeyConstant.UPDATE_ACCOUNT_INFORMATION_MESSAGE, e.getMessage());
        }
        return "account/accountInformation";
    }

    @ResponseBody
    @PostMapping(ServletUrlConstant.LOGIN_SERVLET_URL)
    public String login(@RequestParam(EMAIL_TO_LOGIN) String email,
                        @RequestParam(value = PASSWORD_TO_LOGIN, required = false) String password,
                        @RequestParam(value = "mailVerifyCode", required = false) String verifyCode,
                        HttpSession session) {
        if (password != null && !password.isEmpty()) {
            password = RSAUtils.decrypt(password, privateKey);
            if (password == null) {
                return "Wrong encrypt";
            }
            User user = userService.login(email, password);
            if (user != null) {
                session.setAttribute(SessionAttributeKeyConstant.LOGIN_USER, user);
                return "Main";
            } else {
                return "failed";
            }
        } else if (verifyCode != null) {
            User user = userService.loginWithVerifyCode(email, verifyCode);
            if (user != null) {
                session.setAttribute(SessionAttributeKeyConstant.LOGIN_USER, user);
                return "Main";
            } else {
                return "failed";
            }
        } else {
            return "failed";
        }
    }

    @RequestMapping(ServletUrlConstant.LOGOUT_SERVLET_URL)
    public String logout(HttpSession session) {
        session.setAttribute(SessionAttributeKeyConstant.LOGIN_USER, null);
        return "catalog/main";
    }

    @ResponseBody
    @PostMapping("/account/{email}")
    public Response sendEmail(@Validated @PathVariable String email) {
        //TODO 这里应该判断一下重复发送，重复发送应当被禁止
        if (!RegularExpressionVerifyUtil.isLegalEmailAddress(email)) {
            return Response.build()
                    .status(HttpStatus.FORBIDDEN)
                    .error("邮箱地址非法")
                    .message("请求失败");
        } else {
            Integer res = userService.sendVerificationEmail(email);
            if (res.compareTo(0) > 0) {
                return Response.build()
                        .status(HttpStatus.OK)
                        .message("发送成功");
            } else {
                return Response.build()
                        .status(HttpStatus.FORBIDDEN)
                        .error("邮箱未注册")
                        .message("发送失败");
            }
        }
    }

    @ResponseBody
    @PostMapping("/login/phone/{phoneNumber}")
    public Response sendText(@PathVariable String phoneNumber) {
        //TODO 这里应该判断一下重复发送，重复发送应当被禁止
        if (userService.sendText(phoneNumber)) {
            return Response
                    .build()
                    .status(HttpStatus.OK)
                    .message("发送成功");
        } else {
            return Response.build()
                    .status(HttpStatus.FORBIDDEN)
                    .message("发送失败")
                    .error("手机号未注册，或内部错误");
        }
    }

    @ResponseBody
    @PutMapping("/login/phone/{phoneNumber}")
    public String loginWithPhone(@PathVariable String phoneNumber,
                                 @RequestParam("phoneVerifyCode") String phoneVerifyCode,
                                 HttpSession session) {
        User user = userService.loginWithPhoneVerifyCode(phoneNumber, phoneVerifyCode);
        if (user != null) {
            session.setAttribute(SessionAttributeKeyConstant.LOGIN_USER, user);
            return "Main";
        } else {
            return "failed";
        }
    }

}
